package org.swift.commons.xml;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;


public class NamespaceDefiner {

	private final Map<String, String> namespaces = new HashMap<String, String>();
	
	private Pattern defaultPattern = Pattern.compile("<[\\w-]+( |/>|>)");
	
	public NamespaceDefiner(Map<String, String> namespaces) {
		this.namespaces.putAll(namespaces);
	}
	
	/**
	 * Searches the xml to see if it uses any namespaces in the map then declares then
	 * namespaces on the root node. 
	 * @param string
	 * @return
	 */
	public String defineNamespaces(String string) {
		if (!XmlUtils.isXml(string)) {
			return string;
		}

		
		int endChar = string.indexOf('>');		
		String firstTag = string.substring(0, endChar);
		int endOfFirstTag = firstTag.indexOf(' ');
		if (endOfFirstTag == -1 ) {			
			if (string.charAt(endChar - 1) == '/'){
				endOfFirstTag = --endChar;
			} 		
			endOfFirstTag = endChar;
		}
		StringBuffer result = new StringBuffer(string.substring(0,
				endOfFirstTag));

		
		for (Entry<String, String> namespace : this.namespaces.entrySet()) {
			if ("".equals(namespace.getKey())) {
				java.util.regex.Matcher defaultMatcher = defaultPattern.matcher(string);				
				if (defaultMatcher.find()) { //detect an element without a namespace prefix
					result.append(" xmlns=\"" + namespace.getValue() + "\"");
				}
			} else {
				java.util.regex.Matcher matcher = 
						Pattern.compile("<" + namespace.getKey() + ":[\\w-]+( |/>|>)")
						.matcher(string);
				// DO NOT declare this namespace if it is already present
				// TODO: See if it is a mistake that this namespace is already present.
				if (matcher.find()) {
					String namespaceAttr = " xmlns:" + namespace.getKey() + "="; 
					if (firstTag.indexOf(namespaceAttr) == -1){
						result.append(namespaceAttr +"\""
								+ namespace.getValue() + "\"");
					}
				}
			}
		}
		return result.append(string.substring(endOfFirstTag)).toString();
	}
	
	
}
